
public class RGBImage {
	
	private RGBColor[][] img;
	private int height, width;
	
	/**
	 * constructor to copy RGBImage object image
	 * @param other the RGBImage to copy image from
	 */
	public RGBImage(RGBImage other)
	{	
		img = other.toRGBColorArray();
		height = other.getHeight();
		width = other.getWidth();
	}
	 
	/**
	 * constructor to copy RGBImage from 2D array of RGBColor
	 * @param pixels the 2D array of RGBColor
	 */
	public RGBImage(RGBColor[][] pixels)
	{
		img = new RGBColor[pixels.length][pixels[0].length];
		for (int i = 0; i < pixels.length; i++)
			for (int j = 0; j < pixels[0].length; j++)
			{
				int R = pixels[i][j].getRed();
				int G = pixels[i][j].getGreen();
				int B = pixels[i][j].getBlue();
				img[i][j] = new RGBColor(R, G, B);
			}
		height = pixels.length;
		width = pixels[0].length;
	}
	
	/**
	 * constructor to build black RGBImage   
	 * @param rows the row number of black RGBImage
	 * @param cols the column number of black RGBImage
	 */
	public RGBImage(int rows, int cols)
	{
		img = new RGBColor[rows][cols];
		height = rows;
		width = cols;
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				img[i][j] = new RGBColor(255, 255, 255);
	}
	
	/**
	 * return the image height.
	 * @return image pixel height
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * return the image width
	 * @return image pixel width
	 */
	public int getWidth() {
		return width;
	}
	
	/** getPixel (int row, int col) 
	 * return the RGBColor in the specific coordinate in the image
	 * @param row the row in the image
	 * @param col the column in the image
	 * @return the RGBColor
	 */
	public RGBColor getPixel (int row, int col)
	{
		return img[row][col];
	}
	
	/**
	 * sets the specific RGBColor in the image coordinate to the given pixel
	 * @param row the row in the image
	 * @param col the column in the image
	 * @param pixel the RGBColor to change to
	 */
	public void setPixel(int row, int col, RGBColor pixel)
	{
		if(row<0 || row > getHeight() || col < 0 || col > getWidth())
			return;
		img[row][col] = new RGBColor(pixel);
	}
	
	/**
	 * checks if the given RGBImage matches this RGBImage, by comparing the RGBColor image.
	 * @param other the RGBImage to be compared to
	 * @return true if they equal, false otherwise
	 */
	public boolean equals(RGBImage other)
	{
		for (int i=0; i < getHeight(); i++)
			for (int j = 0; j < getWidth(); j++)
				if (!img[i][j].equals(other.getPixel(i, j)))
					return false;
		return true;
	}
	
	/**
	 * flips the image by mirroring horizontally
	 */
	public void flipHorizontal()
	{
		RGBColor[] temp;
		
		for (int i=0; i < getHeight() / 2; i++)
		{
			temp = img[i];
			img[i] = img[getHeight() - i - 1];
			img[getHeight() - i - 1] = temp;
		}
	}
	
	/**
	 * flips the image by mirroring vertically
	 */
	public void flipVertical()
	{
		RGBColor temp;
		for (int i=0; i< getHeight(); i++)
			for (int j = 0; j < getWidth() / 2; j++)
			{
				temp = img[i][j];
				img[i][j] = img[i][getWidth() - j - 1];
				img[i][getWidth() - j - 1] = temp;
			}
	}
	
	/**
	 * inverts the RGBColors in the image one by one
	 */
	public void invertColors()
	{
		for (int i=0; i< getHeight(); i++)
			for (int j = 0; j < getWidth(); j++)
				img[i][j].invert();
	}
	
	/**
	 * rotate the image clockwise by 90 degrees.
	 */
	public void rotateClockwise()
	{
		RGBColor[][] temp = new RGBColor[width][height];
		for (int i=0; i< getHeight(); i++)
			for (int j = 0; j < getWidth(); j++)
			{
				temp[j][getHeight() - i - 1] = img[i][j];
			}
		img = temp;
		int oldHeight = height;
		height = width;
		width = oldHeight;
	}
	
	/** rotate the image counter clockwise by rotating it 3 times clockwise. 
	 * 
	 */
	public void rotateCounterClockwise()
	{
		rotateClockwise();
		rotateClockwise();
		rotateClockwise();
	}
	
	/**
	 * shift the image columns by offset pixels 
	 * @param offset number of pixel to move the entire image right(or left if offset is negative)
	 */
	public void shiftCol(int offset)
	{
		if (offset > getWidth())
			return;
		if (offset>0)
		{
			for (int i=0; i < getHeight(); i++)
				for (int j = getWidth() - 1; j >= 0; j--)
				{
					if(j < offset)
						img[i][j] = new RGBColor(255,255,255);
					else
						img[i][j] = img[i][j - offset];
				}
		} else
		{
			for (int i = 0; i < getHeight(); i++)
				for (int j = 0; j < getWidth(); j++)
				{
					if(j - offset > getWidth() -1)
						img[i][j] = new RGBColor(255,255,255);
					else 
						img[i][j] = img[i][j - offset];
				}
	
		}
	}
	
	/** 
	 * shift the image rows by offset pixels 
	 * @param offset number of pixel to move the entire image down(or up if offset is negative)
	 */
	public void shiftRow(int offset)
	{
		if (offset > getHeight())
			return;
		if (offset > 0)
		{
			for (int i = getHeight(); i > 0 ; i--)
			{
				if (i < offset)
				{
					for (int j = 0; j < getWidth(); j++)
						img[i][j] = new RGBColor(255,255,255);
				} else
					img[i] = img[i - offset];
			}
		} else
		{
			for (int i = 0; i > getHeight() ; i++)
			{
				if (i - offset > getHeight())
				{
					for (int j = 0; j < getWidth(); j++)
						img[i][j] = new RGBColor(255,255,255);
				} else
				{
					img[i] = img[i - offset];
				}
				
			}	
		}	
	}
	
	/**
	 * return a 2D array of double with grayscale image
	 * @return the 2D grayscale array
	 */
	public double[][] toGrayscaleArray()
	{
		double[][] db = new double[getHeight()][getWidth()];
		for (int i=0; i < getHeight(); i++)
			for (int j = 0; j < getWidth(); j++)
				db[i][j] = img[i][j].convertToGrayScale();
		return db;
	}
	
	public String toString()
	{
		String temp = "";
		for (int i=0; i < getHeight(); i++)
		{
			for (int j = 0; j < getWidth() - 1; j++)
			{
				temp += img[i][j].toString() + " ";
			}
			temp += img[i][getWidth() - 1].toString();
			temp += "\n";
		}
		return temp;
	}
	
	public RGBColor[][] toRGBColorArray()
	{
		RGBColor[][] temp = new RGBColor[getHeight()][getWidth()];
		for (int i=0; i < getHeight(); i++)
			for (int j = 0; j < getWidth(); j++)
				temp[i][j] = new RGBColor(img[i][j]);
		return temp;
	}
}

